#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h> // For atoi function
#include <pthread.h> // For pthreads
#include "mosquitto.h"
#include "cJSON.h"
#include "linux/can.h"
#include "can_rx.h" // Assuming this header defines receive_can_message()

typedef struct s_conn_para {
    char *hostname;
    char *pub_topic;
    char *clientId;
    char *username;
    char *password;
    int port;
    char payload[256];
    char *sub_topic;
    int keepalive;
    int qos;
    pthread_mutex_t mqtt_mutex; // Mutex for MQTT operations
} conn_para_t;

void mqtt_clean(struct mosquitto *mosq);
static void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg);

void *mqtt_subscribe(void *arg);
void *mqtt_publish(void *arg);

    conn_para_t conn_para = {
        "iot-06z00i9k03hcz6s.mqtt.iothub.aliyuncs.com",
        "/sys/h098jXhNP9d/mqtt/thing/event/property/post",
        "h098jXhNP9d.mqtt|securemode=2,signmethod=hmacsha256,timestamp=1720751526199|",
        "mqtt&h098jXhNP9d",
        "16aae5231f7378909fd972fa0212ad774e5e75eb19532d32ccca175232aa7143",
        1883,
        "",
        "/sys/h098jXhNP9d/mqtt/thing/event/property/post_reply",
        60,
        0,
        PTHREAD_MUTEX_INITIALIZER
    };

int main(int argc, char **argv)
{
    struct mosquitto *mosq;
    pthread_t sub_thread, pub_thread;
    int ret;

    const char *interface_name = "can0";


    mosquitto_lib_init();

    mosq = mosquitto_new(conn_para.clientId, true, NULL);

    if (mosquitto_username_pw_set(mosq, conn_para.username, conn_para.password) != MOSQ_ERR_SUCCESS) {
        printf("connect server failure: %s\n", strerror(errno));
        goto cleanup;
    }

    printf("mqtt connect parameters set OK\n");

    if (mosquitto_connect(mosq, conn_para.hostname, conn_para.port, conn_para.keepalive) != MOSQ_ERR_SUCCESS) {
        printf("connect server failure: %s\n", strerror(errno));
        goto cleanup;
    }
    printf("connect ok\n");

    mosquitto_message_callback_set(mosq, my_message_callback);

    // Create thread for subscribing
    ret = pthread_create(&sub_thread, NULL, mqtt_subscribe, (void *)mosq);
    if (ret != 0) {
        printf("Failed to create subscribe thread: %s\n", strerror(ret));
        goto cleanup;
    }

    // Create thread for publishing
    ret = pthread_create(&pub_thread, NULL, mqtt_publish, (void *)mosq);
    if (ret != 0) {
        printf("Failed to create publish thread: %s\n", strerror(ret));
        goto cleanup;
    }

    // Join threads (wait for them to finish)
    pthread_join(sub_thread, NULL);
    pthread_join(pub_thread, NULL);

cleanup:
    mqtt_clean(mosq);
    return 0;
}

void mqtt_clean(struct mosquitto *mosq)
{
    mosquitto_destroy(mosq);
    mosquitto_lib_cleanup();
}

static void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg)
{
    printf("received message: %s\n", (char *)msg->payload);//接收到的字段

    cJSON *root = cJSON_Parse((char *)msg->payload); //根据已经接收到的字段，解析字符串并返回一个句柄
    if (root == NULL) {
        printf("JSON parsing error\n");
        return;
    }

    cJSON *method = cJSON_GetObjectItem(root, "method"); //从json对象中获取指定字段的cJson对象
    if (method != NULL && cJSON_IsString(method)) //参数二是这个对象是判断是否为字符串类型
    {
        if (strcmp(method->valuestring, "thing.service.property.set") == 0) //判断接收的数据是否为所期望的类型 
	{
            cJSON *params = cJSON_GetObjectItem(root, "params");//获取对象
            if (params != NULL) {
                cJSON *can_id = cJSON_GetObjectItem(params, "can_id");
                cJSON *can_dlc = cJSON_GetObjectItem(params, "can_DLC");
                cJSON *can_data = cJSON_GetObjectItem(params, "can_data");

                if (cJSON_IsNumber(can_id) && cJSON_IsNumber(can_dlc) && cJSON_IsNumber(can_data)) //确保字段都是数字类型
	       	{
                    int id = can_id->valueint; //字段
                    int dlc = can_dlc->valueint;
                    int data = can_data->valueint;

                    printf("Received CAN message: id=%d, dlc=%d, data=%d\n", id, dlc, data);//在这里可以添加can发送到单片机的函数
                    // Process the received CAN message here
                } else {
                    printf("Invalid or missing CAN data fields\n");
                }
            } else {
                printf("Missing params object in message\n");
            }
        } else {
            printf("Unsupported method: %s\n", method->valuestring);
        }
    } else {
        printf("Missing or invalid method field\n");
    }

    cJSON_Delete(root);
}

void *mqtt_subscribe(void *arg)
{
    struct mosquitto *mosq = (struct mosquitto *)arg;
    int mid;
    conn_para_t *conn = &conn_para;

    if (mosquitto_subscribe(mosq, &mid, conn->sub_topic, conn->qos) != MOSQ_ERR_SUCCESS) {
        printf("mosquitto subscribe failure: %s\n", strerror(errno));
        return NULL;
    }
    printf("subscribe OK\n");

    while (1) {
        if (mosquitto_loop(mosq, -1, 1) != MOSQ_ERR_SUCCESS) {
            printf("Mosquitto loop error\n");
            break;
        }
    }

    return NULL;
}

void *mqtt_publish(void *arg)
{
    struct mosquitto *mosq = (struct mosquitto *)arg;
    int mid1;
    conn_para_t *conn = &conn_para;

    while (1) {
        struct can_frame received_frame = receive_can_message("can0");
        snprintf(conn->payload, sizeof(conn->payload), "{\"method\":\"thing.service.property.set\",\"id\":\"10353468\",\"params\":{\"can_id\":%d,\"can_DLC\":%d,\"can_data\":%d},\"version\":\"1.0.0\"}",
                 (int)received_frame.can_id, (int)received_frame.can_dlc, (int)received_frame.data[1]);

        pthread_mutex_lock(&conn->mqtt_mutex);
        int ret = mosquitto_publish(mosq, &mid1, conn->pub_topic, strlen(conn->payload), conn->payload, conn->qos, 0);
        pthread_mutex_unlock(&conn->mqtt_mutex);

        if (ret != MOSQ_ERR_SUCCESS) {
            printf("mosquitto publish data failure: %s\n", strerror(errno));
            continue;
        }
        printf("published message: %s\n", conn->payload);
        sleep(3);
    }

    return NULL;
}

